// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

/*!
\file 
\brief Implementation of Statistical Sorting Functions
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "copyfile.h"
#include "options.h"
#include "types.h"
#include "sort.h"
#include "suffixes.h"
#include "utils.h"

#define MAX_LINE_LENGTH 256
#define MAX_TOKEN_LENGTH 80

/*!
\brief Sorted Line of Text
*/
struct sorted_line {
	char line[MAX_LINE_LENGTH];
	double value;
};

// Function does reverse ordering.
int sorted_line_compare(const void* p1, const void* p2) {
	const struct sorted_line **a = (const struct sorted_line **) p1;
	const struct sorted_line **b = (const struct sorted_line **) p2;

	if (a == NULL || b == NULL) return 0;

	if ((*a)->value < (*b)->value) return -1;
	else if ((*a)->value == (*b)->value) return 0;
	else if ((*a)->value > (*b)->value) return 1;
	else return 0;
}

// Sort a CSV file
int sort_file(char *filepath, int sort_col_index) {
	int nLines = 0;
	FILE *in = NULL, *out = NULL;
	char line[MAX_LINE_LENGTH], token[MAX_TOKEN_LENGTH], headers[MAX_LINE_LENGTH];
	int i;
	struct sorted_line **data = NULL;
	struct sorted_line **pData = NULL;
	int alloc_count = 0;
	char output_file[FILE_PATH_LENGTH];

	// Get the number of lines.
	if ((in = fopen(filepath, "r")) == NULL) return 0;
	while(fgets(line, MAX_LINE_LENGTH, in) != NULL) {
		if (strlen(line) > 0) 
			nLines++;
	}
	fclose(in);

	// Allocate memory for the sort buffer.
	data = (struct sorted_line**) malloc(sizeof(struct sorted_line*) * (nLines - 1)); // Header Line
	if (data == NULL) return 0;
	for (i = 0, pData = data; i < nLines - 1; i++, pData++) {
		*pData = NULL;
		*pData = (struct sorted_line*) malloc(sizeof(struct sorted_line));
		if (*pData != NULL) alloc_count++;
	}
	
	// Re-open the file.
	in = fopen(filepath, "r");
	if (in == NULL) {
		for (i = 0, pData = data; i < nLines - 1; i++, pData++) {
			if (*pData) free(*pData);
		}
		free(data);
		return 0;
	}
	fgets(headers, MAX_LINE_LENGTH, in);
	pData = data;
	while(fgets(line, MAX_LINE_LENGTH, in) != NULL) {
		char *p = NULL, *q = NULL;
		int tokenCount = 0;

		if (strlen(line) == 0) continue;

		// Initialise the line buffer.
		strcpy((*pData)->line, line);
		(*pData)->value = -1;

		p = line;
		while (*p) {
			q = token;
			while((*p != ',' && *p != '\r' && *p != '\n') && *p) { 
				*q = *p;
				q++; p++;
			}
			if (*p) p++; // advance past the space
			*q = '\0'; // NULL terminate the token

			if (strlen(token) == 0) continue;

			tokenCount++;
			if (sort_col_index == tokenCount) {
				if (strcmp(token, "NA") != 0)
					(*pData)->value = (double) atof(token);
				else 
					(*pData)->value = 1.0;
				break;
			}
		}

		pData++;
	}
	fclose(in);

	// Quick-sort the data buffer.
	qsort(data, nLines - 1, sizeof(struct sorted_line*), sorted_line_compare);

	// Write the sort output to a new file.
	strcpy(output_file, filepath);
	strcat(output_file, SUFFIX_SORTED_FILE);
	out = fopen(output_file, "w");
	if (out == NULL) {
		for (i = 0, pData = data; i < nLines - 1; i++, pData++) {
			if (*pData) free(*pData);
		}
		free(data);
		return 0;
	}

	fprintf(out, "%s", headers);
	for (i = 0, pData = data; i < nLines - 1; i++, pData++) 
		fprintf(out, "%s", (*pData)->line);
	fclose(out);
	

	// Free-up used memory.
	if (data != NULL) {
		for (i = 0, pData = data; i < nLines - 1; i++, pData++) {
			if (*pData) free(*pData);
		}
		free(data);
	}

	return 1;  // Get here, file sort was successful.
}

int sort_file_by_col_and_copy(char *localFilepath, char *remoteFilepath, char *colName) {
	int columnIndex = -1;
	FILE *in = NULL;
	char line[1024]; // Just for the header line only.

	if (localFilepath == NULL || remoteFilepath == NULL || colName == NULL) return 0;
	else if (strlen(localFilepath) == 0 || strlen(remoteFilepath) == 0 || strlen(colName) == 0) return 0;

	if ((in = fopen(localFilepath, "r")) == NULL) return 0;
	if (fgets(line, 1024, in)) {
		int nColumns = get_number_of_tokens(line, ','), i;
		if (nColumns > 0) {
			char token[80];
			for (i = 0; i < nColumns; i++) {
				if(get_token(line, token, i, ',')) {
					if (strcmp(token, colName) == 0) {
						columnIndex = i + 1;
						break;
					}
				}
			}
		}
	}
	fclose(in);
	if (columnIndex == -1) return 0;

	if (sort_file(localFilepath, columnIndex)) {
		if (deleteFile(localFilepath)) {
			strcat(localFilepath, SUFFIX_SORTED_FILE);
			if (copyAndDeleteFile(localFilepath, remoteFilepath)) return 1;
		}
	}

	return 0;
}

